#ifndef ROBOTSUBSYSTEM_H
#define ROBOTSUBSYSTEM_H

#include "WPILib.h"
#include "../Subscriber.hpp"

/**
 *  The RobotSubsystem class is a base class for classes that represent a subsystem of the robot.
 *  
 *  A subsystem usually represents a mechanism on the physical robot. (e.g. A DriveSubsystem would represent the drive train.)
 *  
 *  To use it, create subclasses that override HandlePeriodic, HandleStop, and (optionally) HandleAwake functions.
 *  Then, create functions that control the subsystem that to be called by external Services or internal Operations.
 *  
 *  Every RobotSubsystem must be added to the SystematicRobot,
 *  which will call the event handling functions at the correct times.
 *  
 *  Subsystems can be set asleep by calling Sleep to save processing time.
 *  While asleep, HandlePeriodic will not be called and no Operations can be run within it.
 *  Use the Awake function to exit this sleep mode.
 *  
 *  Testing shows this class works.
 */
class RobotSubsystem :
	public Subscriber
{
	// Befriend our robot class so it can call our functions.
	friend class SystematicRobot;
	
	public:
		RobotSubsystem();
		virtual ~RobotSubsystem();
		
		void Stop();
	protected:
		/**
		 *  The Action class represents an Action being run on the subsystem.  (Not to be confused with Operation.)
		 *  
		 *  The main function of this class is to provide thread safety to the subsystem.
		 *  To use it, declare a local variable of type "Action" within any public function of the subsystem (called an "Action" function) and pass "this" to it's constructor.
		 *  
		 *  For more information on thread safety, see our Thread Safety Manuel that does not exist yet. :P 
		 */
		class Action
		{
			public:
				Action(const RobotSubsystem *subsystem, bool takeSemaphore = true);
				~Action();
			private:
				ReentrantSemaphore *m_semaphorePtr;
		};
		
		virtual void HandlePeriodic();
		virtual void HandleAwake();
		
		/**
		 *  This function must be overridden to disable this subsystem.
		 *  
		 *  It must be implimented such that:
		 *    - All contained actuators will stop.
		 *    - The subsystem can be stopped again even after it has been stopped.
		 *    - Actuators will stay powerless until an Action function (a public function) has been called.
		 *    - If the subsystem has already been stopped and an Action function has not been called, stopping the subsystem will not result in powered actuator activity.
		 */
		virtual void HandleStop() = 0;
		
		bool GetIsAwake() const;
		void Awake();
		void Sleep();
	private:
		mutable ReentrantSemaphore m_semaphore;
};

#endif // #ifndef ROBOTSUBSYSTEM_H 
